// 引入three.js
import * as THREE from 'three';
// 导入附加组件-轨道控制器
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入CSS3渲染器CSS3DRenderer
import { CSS3DRenderer } from 'three/addons/renderers/CSS3DRenderer.js';

import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from "three/addons/postprocessing/RenderPass"
import { OutlinePass } from "three/addons/postprocessing/OutlinePass"
import { ShaderPass } from "three/addons/postprocessing/ShaderPass"
// SMAA抗锯齿通道
import { SMAAPass } from 'three/addons/postprocessing/SMAAPass.js';
import { GammaCorrectionShader } from 'three/addons/shaders/GammaCorrectionShader.js';

export let scene, camera, renderer, controls, css3DRenderer, width, height, composer, renderPass, outlinePass

// 1.初始化三要素
export function init (dom) {
  scene = new THREE.Scene();
  // 设置场景颜色
  scene.background = new THREE.Color(0x001c55)
  camera = new THREE.PerspectiveCamera(25, width / height, 1, 1000);
  // 移动相机位置
  camera.position.set(0, 0, 80);
  camera.lookAt(new THREE.Vector3(0, 0, 0));
  // 添加抗锯齿效果
  renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true, });
  // 给画布设置宽高
  renderer.setSize(width, height);
  // document.body.appendChild(renderer.domElement);
  dom.appendChild(renderer.domElement);
}

// 2.创建轨道控制器
export function createControls () {
  controls = new OrbitControls(camera, renderer.domElement);
  // 开启阻尼惯性
  controls.enableDamping = true;
  // 阻尼速度
  controls.dampingFactor = 0.1;
  // 开启旋转
  // controls.autoRotate = true;
  // 旋转的速度
  // controls.autoRotateSpeed = 1;
  // 视角最小距离
  // controls.minDistance = 20;
  // 视角最远距离
  // controls.maxDistance = 5000;
  // 最大角度
  controls.maxPolarAngle = Math.PI / 3;
}

// 3.初始化灯光
export function initLight () {
  //模拟远处类似太阳的光源
  const directionalLight = new THREE.DirectionalLight(0xffffff, 1); //模拟远处类似太阳的光源
  directionalLight.position.set(3, 500, 10).normalize();
  scene.add(directionalLight);
  //影响整个场景的光源
  const ambient = new THREE.AmbientLight(0xffffff, 1);
  ambient.position.set(0, 500, 10);
  scene.add(ambient);
}

// 4.创建CSS3D渲染器
export const createCSS3DRenderer = (dom) => {
  // 创建一个CSS3渲染器CSS3DRenderer
  css3DRenderer = new CSS3DRenderer();
  css3DRenderer.setSize(180, 200);
  // HTML标签<div id="dialog"></div>外面父元素叠加到canvas画布上且重合
  css3DRenderer.domElement.style.position = 'absolute';
  css3DRenderer.domElement.style.top = '0';
  // css3DRenderer.domElement.style.left = '0px';
  //设置.pointerEvents=none，解决HTML元素标签对threejs canvas画布鼠标事件的遮挡
  css3DRenderer.domElement.style.pointerEvents = 'none';
  // threeDemoRef.value.appendChild(css3DRenderer.domElement);
  dom.appendChild(css3DRenderer.domElement);
};

// 5.1监测div的尺寸变化(是否大屏/全屏)
export const watchDom = (dom) => {
  let ro = new ResizeObserver(() => {
    updateRelatedProperties(dom)
  });
  ro.observe(dom);
};

// 5.2监听浏览器窗口的缩放
export function renderResize (dom) {
  window.addEventListener('resize', () => {
    updateRelatedProperties(dom)
  });
}

// 6.循环渲染
export function renderLoop () {
  requestAnimationFrame(renderLoop);
  // 实时更新性能
  controls.update();
  css3DRenderer.render(scene, camera);
  renderer.render(scene, camera);
  if (composer) {
    composer.render()
  }

}

// -------------------------功能交互-------------------------

// 获取鼠标和射线的相交点
export function getIntersectPoint (event) {
  // 鼠标控制对象
  const mouse = new THREE.Vector2();
  // 初始化射线辅助器
  const raycaster = new THREE.Raycaster();
  // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
  let rect = renderer.domElement.getBoundingClientRect()
  mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
  mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
  //通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
  raycaster.setFromCamera(mouse, camera);
  // 获取与射线相交的对象数组，其中的元素按照距离排序，越近的越靠前
  return raycaster.intersectObjects(scene.children, true);
}

// 添加呼吸灯效果
export function addOutlineEffect (selectedObjects, color) {
  composer = new EffectComposer(renderer);
  renderPass = new RenderPass(scene, camera);
  composer.addPass(renderPass);

  outlinePass = new OutlinePass(new THREE.Vector2(width, height), scene, camera);
  outlinePass.selectedObjects = selectedObjects
  outlinePass.edgeStrength = 8; // 发光的强度
  outlinePass.edgeGlow = 1; // 光晕
  outlinePass.usePatternTexture = false // 是否使用父级的材质
  outlinePass.edgeThickness = 8; // 边框的宽度
  outlinePass.downSampleRatio = 1 // 边框弯曲度
  outlinePass.pulsePeriod = 3; // 呼吸灯闪烁的速度
  outlinePass.visibleEdgeColor.set(color); // 呼吸显示的颜色
  outlinePass.hiddenEdgeColor.set(color); // 呼吸消失的颜色
  outlinePass.clear = true
  composer.addPass(outlinePass);

  //获取.setPixelRatio()设置的设备像素比
  const pixelRatio = renderer.getPixelRatio();
  // 抗锯齿
  const smaaPass = new SMAAPass(width * pixelRatio, height * pixelRatio);
  composer.addPass(smaaPass);

  // 模型颜色修正
  const gammaCorrectionShader = new ShaderPass(GammaCorrectionShader);
  composer.addPass(gammaCorrectionShader);
}


// --------------------------公共函数-------------------------------
export const getDomInfo = (dom) => {
  width = dom.offsetWidth;
  height = dom.offsetHeight;
};

function updateRelatedProperties (dom) {
  getDomInfo(dom);
  // 更新画布宽高
  renderer.setSize(width, height);
  // 更新相机的宽高比
  camera.aspect = width / height;
  // 更新相机的近截面和远截面
  camera.updateProjectionMatrix();
  // HTML标签css3Renderer.domElement尺寸重新设置
  css3DRenderer.setSize(width, height);
}

